package cn.iocoder.yudao.module.energy.controller.admin.alert;

import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import org.springframework.validation.annotation.Validated;
import javax.validation.Valid;
import org.springframework.web.multipart.MultipartFile;
import java.io.IOException;
import java.io.InputStream;
import java.time.LocalDateTime;
import java.util.*;
import javax.servlet.http.HttpServletResponse;

import io.swagger.v3.oas.annotations.tags.Tag;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.Operation;

import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.pojo.PageParam;

import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog;
import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.*;

import cn.iocoder.yudao.module.energy.controller.admin.alert.vo.*;
import cn.iocoder.yudao.module.energy.service.alert.AlertService;
import cn.iocoder.yudao.module.energy.dal.dataobject.alert.EnergyAlertDO;
import cn.iocoder.yudao.module.energy.convert.alert.AlertConvert;
import cn.iocoder.yudao.module.energy.dal.mysql.data.DataMapper;
import cn.iocoder.yudao.module.energy.dal.dataobject.data.DataDO;

import java.math.BigDecimal;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;

import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;

@Tag(name = "管理后台 - 预警")
@RestController
@RequestMapping("/energy/alert")
@Validated
public class AlertController {

    @Resource
    private AlertService alertService;
    
    @Resource
    private DataMapper dataMapper;

    @PostMapping("/create")
    @Operation(summary = "创建预警")
    public CommonResult<Long> createAlert(@Valid @RequestBody AlertSaveReqVO createReqVO) {
        return success(alertService.createAlert(createReqVO));
    }

    @PutMapping("/update")
    @Operation(summary = "更新预警")
    public CommonResult<Boolean> updateAlert(@Valid @RequestBody AlertSaveReqVO updateReqVO) {
        alertService.updateAlert(updateReqVO);
        return success(true);
    }

    @DeleteMapping("/delete")
    @Operation(summary = "删除预警")
    @Parameter(name = "id", description = "编号", required = true)
    public CommonResult<Boolean> deleteAlert(@RequestParam("id") Long id) {
        alertService.deleteAlert(id);
        return success(true);
    }

    @GetMapping("/get")
    @Operation(summary = "获得预警")
    @Parameter(name = "id", description = "编号", required = true, example = "1024")
    public CommonResult<AlertRespVO> getAlert(@RequestParam("id") Long id) {
        EnergyAlertDO alert = alertService.getAlert(id);
        return success(AlertConvert.INSTANCE.convert(alert));
    }

    @GetMapping("/page")
    @Operation(summary = "获得预警分页")
    public CommonResult<PageResult<AlertRespVO>> getAlertPage(@Valid AlertPageReqVO pageVO) {
        PageResult<EnergyAlertDO> pageResult = alertService.getAlertPage(pageVO);
        
        // 打印数据，检查level字段值
        for (EnergyAlertDO alert : pageResult.getList()) {
            System.out.println("Alert ID: " + alert.getId() + ", Level: " + alert.getLevel());
        }
        
        PageResult<AlertRespVO> pageResultVO = AlertConvert.INSTANCE.convertPage(pageResult);
        
        // 检查转换后的level值
        for (AlertRespVO alertVO : pageResultVO.getList()) {
            System.out.println("AlertVO ID: " + alertVO.getId() + ", Level: " + alertVO.getLevel());
            
            // 如果level为空，但原始对象中有值，则手动设置
            if (alertVO.getLevel() == null) {
                // 查找对应的原始对象
                for (EnergyAlertDO alert : pageResult.getList()) {
                    if (alert.getId().equals(alertVO.getId()) && alert.getLevel() != null) {
                        alertVO.setLevel(alert.getLevel());
                        System.out.println("手动设置 Level: " + alertVO.getId() + ", Level: " + alertVO.getLevel());
                        break;
                    }
                }
            }
        }
        
        // 从列表中获取所有设备ID
        Set<String> deviceIds = new HashSet<>();
        for (AlertRespVO alertVO : pageResultVO.getList()) {
            if (alertVO.getDeviceId() != null) {
                deviceIds.add(alertVO.getDeviceId());
            }
        }
        
        // 如果有设备ID，查询设备名称
        if (!deviceIds.isEmpty()) {
            // 从energy_data表获取设备名称
            Map<String, String> deviceNameMap = new HashMap<>();
            
            // 批量查询设备数据
            List<DataDO> dataList = dataMapper.selectLatestByDeviceIds(deviceIds);
            for (DataDO data : dataList) {
                if (data.getDeviceId() != null && data.getDeviceName() != null) {
                    deviceNameMap.put(data.getDeviceId(), data.getDeviceName());
                }
            }
            
            // 填充设备名称
            for (AlertRespVO alertVO : pageResultVO.getList()) {
                if (alertVO.getDeviceId() != null && deviceNameMap.containsKey(alertVO.getDeviceId())) {
                    alertVO.setDeviceName(deviceNameMap.get(alertVO.getDeviceId()));
                }
            }
        }
        
        return success(pageResultVO);
    }

    @GetMapping("/export-excel")
    @Operation(summary = "导出预警 Excel")
    @ApiAccessLog(operateType = EXPORT)
    public void exportAlertExcel(@Valid AlertPageReqVO pageVO,
                           HttpServletResponse response) throws IOException {
        // 设置为不分页，查询所有数据
        pageVO.setPageSize(PageParam.PAGE_SIZE_NONE);
        // 查询数据
        List<EnergyAlertDO> list = alertService.getAlertPage(pageVO).getList();
        
        // 打印日志，查看是否有数据
        System.out.println("======导出预警数据条数：" + list.size());
        
        // 转换成VO列表 - 使用转换工具手动转换，确保所有字段都被正确转换
        List<AlertRespVO> voList = new ArrayList<>(list.size());
        for (EnergyAlertDO alertDO : list) {
            AlertRespVO vo = AlertConvert.INSTANCE.convert(alertDO);
            // 确保level字段正确设置
            if (vo.getLevel() == null && alertDO.getLevel() != null) {
                vo.setLevel(alertDO.getLevel());
            }
            voList.add(vo);
        }
        
        // 获取所有设备ID
        Set<String> deviceIds = new HashSet<>();
        for (EnergyAlertDO alert : list) {
            if (alert.getDeviceId() != null) {
                deviceIds.add(alert.getDeviceId());
            }
        }
        
        // 如果有设备ID，查询设备名称并填充
        if (!deviceIds.isEmpty()) {
            Map<String, String> deviceNameMap = new HashMap<>();
            List<DataDO> dataList = dataMapper.selectLatestByDeviceIds(deviceIds);
            for (DataDO data : dataList) {
                if (data.getDeviceId() != null && data.getDeviceName() != null) {
                    deviceNameMap.put(data.getDeviceId(), data.getDeviceName());
                }
            }
            
            // 填充设备名称
            for (AlertRespVO alertVO : voList) {
                if (alertVO.getDeviceId() != null && deviceNameMap.containsKey(alertVO.getDeviceId())) {
                    alertVO.setDeviceName(deviceNameMap.get(alertVO.getDeviceId()));
                }
            }
        }
        
        // 打印导出的数据
        for (AlertRespVO vo : voList) {
            System.out.println("导出数据: ID=" + vo.getId() + ", Type=" + vo.getAlertType() 
                             + ", Level=" + vo.getLevel() + ", DeviceName=" + vo.getDeviceName());
        }
        
        // 导出Excel
        ExcelUtils.write(response, "能耗预警.xls", "数据", AlertRespVO.class, voList);
    }

    @PostMapping("/upload")
    @Operation(summary = "批量上传预警数据")
    @ApiAccessLog(operateType = CREATE)
    public CommonResult<Integer> uploadAlerts(@RequestParam("file") MultipartFile file) throws IOException {
        if (file.isEmpty()) {
            return success(0);
        }
        
        // 校验文件类型
        String fileName = file.getOriginalFilename();
        if (fileName == null || !fileName.toLowerCase().endsWith(".json")) {
            throw new IllegalArgumentException("只支持上传JSON文件");
        }
        
        // 读取JSON文件内容
        String jsonContent;
        try (InputStream inputStream = file.getInputStream();
             java.io.ByteArrayOutputStream result = new java.io.ByteArrayOutputStream()) {
            // 使用缓冲区读取
            byte[] buffer = new byte[1024];
            int length;
            while ((length = inputStream.read(buffer)) != -1) {
                result.write(buffer, 0, length);
            }
            jsonContent = result.toString("UTF-8");
        }
        
        // 解析JSON数据为对象列表
        List<Map<String, Object>> alertDataList;
        try {
            ObjectMapper objectMapper = new ObjectMapper();
            alertDataList = objectMapper.readValue(jsonContent, new TypeReference<List<Map<String, Object>>>() {});
        } catch (JsonProcessingException e) {
            throw new IllegalArgumentException("JSON格式错误: " + e.getMessage());
        }
        
        // 校验数据并插入
        int successCount = 0;
        List<EnergyAlertDO> alerts = new ArrayList<>();
        
        for (Map<String, Object> alertData : alertDataList) {
            try {
                // 校验必填字段
                if (!validateAlertData(alertData)) {
                    continue;
                }
                
                // 转换为DO对象
                EnergyAlertDO alert = new EnergyAlertDO();
                alert.setAlertType(String.valueOf(alertData.get("alertType")));
                alert.setAlertValue(new BigDecimal(String.valueOf(alertData.get("alertValue"))));
                alert.setThreshold(new BigDecimal(String.valueOf(alertData.get("threshold"))));
                alert.setMessage(String.valueOf(alertData.get("message")));
                alert.setLevel(String.valueOf(alertData.get("level")));
                alert.setAlertTime(LocalDateTime.now());
                alert.setStatus("0"); // 默认未处理
                
                // 设置设备ID
                if (alertData.containsKey("deviceId")) {
                    alert.setDeviceId(String.valueOf(alertData.get("deviceId")));
                } else {
                    // 如果没有设备ID，跳过该条数据
                    continue;
                }
                
                alerts.add(alert);
                successCount++;
            } catch (Exception e) {
                // 跳过无效数据
                System.err.println("处理预警数据失败: " + e.getMessage());
            }
        }
        
        // 批量插入数据
        if (!alerts.isEmpty()) {
            alertService.batchCreateAlerts(alerts);
        }
        
        return success(successCount);
    }
    
    /**
     * 校验预警数据
     */
    private boolean validateAlertData(Map<String, Object> alertData) {
        // 校验必填字段
        if (!alertData.containsKey("alertType") || !alertData.containsKey("alertValue") || 
            !alertData.containsKey("threshold") || !alertData.containsKey("message") ||
            !alertData.containsKey("level") || !alertData.containsKey("deviceId")) {
            return false;
        }
        
        // 校验字段类型
        try {
            String alertType = String.valueOf(alertData.get("alertType"));
            new BigDecimal(String.valueOf(alertData.get("alertValue")));
            new BigDecimal(String.valueOf(alertData.get("threshold")));
            String message = String.valueOf(alertData.get("message"));
            String level = String.valueOf(alertData.get("level"));
            String deviceId = String.valueOf(alertData.get("deviceId"));
            
            // 校验设备ID不能为空
            if (deviceId == null || deviceId.trim().isEmpty()) {
                return false;
            }
            
            // 校验告警类型
            boolean validAlertType = Arrays.asList("voltage", "currents", "active_power", 
                                                "energy_consumption", "temperature")
                                      .contains(alertType);
            if (!validAlertType) {
                return false;
            }
            
            // 校验告警级别
            boolean validLevel = Arrays.asList("warning", "danger").contains(level);
            if (!validLevel) {
                return false;
            }
            
            return true;
        } catch (Exception e) {
            return false;
        }
    }

} 